
using OhioState.AssetManaged;
using OhioState.Graphics;
using OhioState.Graphics.Proxy;
using OhioState.Math;
using Tao.OpenGl;

namespace OhioState.Graphics.OpenGL
{
    public class ROIBoxHandler : OpenGLObject, IDrawable
    {
        //public enum SlicingType { OBJECT_ALIGNED, IMAGE_ALIGNED, OTHER };
        //public static SlicingType slicingAlignment = SlicingType.IMAGE_ALIGNED;
        public IMaterial Material
        {
            get { return _boxProxy.Material; }
            set { }
        }
        public IBoundingVolume BoundingVolume
        {
            get { return _boxProxy.BoundingVolume; }
        }

        public int DrawablePosition
        {
            get { return _realROIBox.DrawablePosition; }
            set { _realROIBox.DrawablePosition = value; }
        }
       
        public float SliceThickness
        {
            get { return _realROIBox.SliceThickness; }
            set { _realROIBox.SliceThickness = value; }
        }
        private SliceDirection.SliceDirMode _sliceMode;
        public SliceDirection.SliceDirMode SlicingMode
        {
            get { return _sliceMode; }
            set { _sliceMode = value; }
        }
        public Vector3 SliceDirection
        {
            get { return _realROIBox.SliceDirection; }
            set { _realROIBox.SliceDirection = value; }
        }
        public Matrix4 WorlToROIMatrix
        {
            get { return _realROIBox.WorlToROIMatrix; }
            set { _realROIBox.WorlToROIMatrix = value; }

        }
        public Matrix4 ROIToTextureMatrix
        {
            get { return _realROIBox.ROIToTextureMatrix; }
            set { _realROIBox.ROIToTextureMatrix = value; }
        }
        private ROIBoxProxy _boxProxy;
        private ROIBoxGL _realROIBox;
        public ROIBoxHandler( ROIBoxProxy proxyObj )
            : base(proxyObj)
        {
            _boxProxy = proxyObj;
            _realROIBox = new ROIBoxGL(_boxProxy.BoundingVolume as BoundingBox);
        }

        public void Render(IRenderPanel panel)
        {
            Update(panel);
            Vector3 direction = UpdateSliceDirection(_boxProxy.SlicingMode, _boxProxy.SliceDirection);
            _realROIBox.SliceDirection = direction;
            _realROIBox.Render(panel);
        }

        public override void Update(IRenderPanel panel)
        {
            if (this.Invalid)
            {
                this.Invalid = false;
                _realROIBox = new ROIBoxGL(_boxProxy.BoundingVolume as BoundingBox);
                _realROIBox.SliceThickness = _boxProxy.SliceThickness;
                _realROIBox.SliceDirection = new Vector3(_boxProxy.SliceDirection);
                _realROIBox.WorlToROIMatrix = new Matrix4(_boxProxy.WorlToROIMatrix);
                _realROIBox.ROIToTextureMatrix = new Matrix4(_boxProxy.ROIToTextureMatrix);
                _realROIBox.Material = panel.ResourceManager.GetItem(_boxProxy.Material as IAssetManaged) as IMaterial;
            }
        }
        public static Vector3 UpdateSliceDirection( SliceDirection.SliceDirMode sliceMode, Vector3 direction )
        {
            float x = 0.0f, y = 0.0f, z = 0.0f;
            Vector3 sliceDirection = null;
            Vector3 xAxis = new Vector3(1.0f, 0.0f, 0.0f);
            Vector3 yAxis = new Vector3(0.0f, 1.0f, 0.0f);
            Vector3 zAxis = new Vector3(0.0f, 0.0f, 1.0f);
            float sign = 1.0f;
            float[] entries = new float[16];
            Vector4 eyeImage = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
            Gl.glGetFloatv(Gl.GL_MODELVIEW_MATRIX, entries);
            Matrix4 modelView = new Matrix4(entries);
            Matrix4 inverseModelView = Matrix4.inverse(modelView);
            Vector4 eyeWorld = inverseModelView * eyeImage;
            //
            // Determine the slice direction
            //    This routine supports either image-aligned or world-aligned.
            //
            
            if (sliceMode == OhioState.Graphics.Proxy.SliceDirection.SliceDirMode.VIEW_ALIGNED)
            {
                //
                // Image-aligned slicing, just pass back the viewing ray in world-space.
                //
                eyeWorld.normalize();
                x = eyeWorld[0];
                y = eyeWorld[1];
                z = eyeWorld[2];
                sliceDirection = new Vector3(x, y, z);
            }
            else if (sliceMode == OhioState.Graphics.Proxy.SliceDirection.SliceDirMode.WORLD_ALIGNED)
            {
                //
                // World-aligned (back-to-front):
                // Find the maximum component and the sign
                //
                int pos = 0;
                if (System.Math.Abs(eyeWorld[pos]) < System.Math.Abs(eyeWorld[1])) pos = 1;
                if (System.Math.Abs(eyeWorld[pos]) < System.Math.Abs(eyeWorld[2])) pos = 2;
                if (eyeWorld[pos] < 0.0f) sign = -1.0f;
                switch (pos)
                {
                    case 0:
                        x = sign * xAxis[0];
                        y = sign * xAxis[1];
                        z = sign * xAxis[2];
                        break;
                    case 1:
                        x = sign * yAxis[0];
                        y = sign * yAxis[1];
                        z = sign * yAxis[2];
                        break;
                    case 2:
                        x = sign * zAxis[0];
                        y = sign * zAxis[1];
                        z = sign * zAxis[2];
                        break;
                }
                sliceDirection = new Vector3(x, y, z);
            }
            else if (sliceMode == OhioState.Graphics.Proxy.SliceDirection.SliceDirMode.FIXED_WORLD_DIR)
            {
                sliceDirection = direction;
            }
            else if (sliceMode == OhioState.Graphics.Proxy.SliceDirection.SliceDirMode.FIXED_VIEW_DIR)
            {
                Vector4 dir = new Vector4(direction, 0.0f);
                eyeWorld = inverseModelView * dir;
                eyeWorld.normalize();
                x = eyeWorld[0];
                y = eyeWorld[1];
                z = eyeWorld[2];
                sliceDirection = new Vector3(x, y, z);
            }
            return sliceDirection;
        }
    }
}
